#ifndef VM_H
#define VM_H

#define FRAMES 100 //amount of frames in memory

#include <stdlib.h>
#include <stdio.h>
#include "semaphore.h"
#include "queue.h"
#include "paging.h"

/*define our word size*/
typedef char word[5];

/*Struct that represents a brain10 virtual machine.*/
typedef struct brain10_t{
	word memory[100][10];
	word shared[100];            /* added in project 3 */
	semaphore semaphores[100];   /* added in project 3 */
	char* R;  // register
	char* IC; // counter
	char* SP; // stack pointer
	char* BR; // base register
	char* LR; // limit register
	char* C;     // bool
	char* PID; // process id
	pageTable* pt;
	pcb* activePcb;
}brain10;

brain10* brain_vm;
list* brain_rdyQ;
list* brain_unloadedQ;
list* brain_freePages;
int halted; //set to 1 during a halt

/* project 4
 * Struct representing a process that has not
 * yet been loaded into memory. If it exists after
 * the VM starts executing other process's instructions
 * then there must have not been any room for it.
 */
typedef struct proc_t{
	char PID[3]; // process id
	int pagesNeeded; //requestd pages in file
	int ic; //number of instructions held
	list instructions;
}process;


/*print the contents of the vm*/
void print(brain10 *vm);

/* project 4
 * prints out the page table of each process
 * in a given queue.
 * @param queue A list where the data is of type process
 */
void printPageTable(list* queue);

void initSemaphores(brain10* vm, int value);

/* project 4
 * This functions causes the vm to check the unloadedQ
 * for any process waiting to be loaded into memory, finds
 * it pages to use and logs the pages in that processes 
 * page table. Finally, after loading, the processes will be
 * appended to the rdyQ as a pcb
 * @param rdyQ The ready queue that new processes are appended to
 * @param unloadedQ The queue that holds all processes waiting to be
 * loaded into memory (because there was no room for them perhaps)
 * @param freePages A list (queue) of free pages that is used to 
 * allocate memory for new processes based on the amount of pages
 * that they request in the source file (second line of code)
 */
void loadProcesses(brain10 *vm, list* rdyQ, list* unloadedQ, list* freePages);

/* project 4 
 * Takes a virtual address and a page table and
 * translates it into a physical address
 */
int translateAddress(char* address, pageTable* pt);

/* project 4
 * Simple helper function to check that the
 * requested pages is no higher than 10 and
 * no less than 0 (saves space)
 * @param pages The number to test
 */
int checkPages(int pages);

/* project 4
 * simple helper function to check that the
 * string equals "BRAIN10"
 * @param string The string to check
 */
void checkTitle(char* string);

/* project 3
 * this function needs to be called in order to use
 * semaphores. It tells the semaphores which ready queue
 * they are receiving waits and signals from, and where
 * processes should be placed when they are removed from a
 * semaphore queue.
 */
void setReadyQ(list* readyQ); /* added in project 3 */

/* project 3
 * calculates the BR of the next process
 * based on the current amount of instructions
 * read.
 */
int calcBR(int current);

/*saves vm state to a process control block*/
void storeContext(pcb* block, brain10* vm);
void loadContext(brain10* vm, pcb* block);
void reset(brain10* vm);

/*Load a program into the vm*/
FILE* loadProgram(brain10 *vm, char fileName[], list* rdyQ, list* unloadedQ, list* freePages);

void LR(brain10 *vm, char* address);//done
void LL(brain10 *vm, char* address);//done
void LH(brain10 *vm, char* address);//done
void SR(brain10 *vm, char* address);//done


void SP(brain10 *vm);//done
void PS(brain10 *vm);//done
void PH(brain10 *vm);//done
void PP(brain10 *vm);//done

void CE(brain10 *vm, char* address);//done
void CL(brain10 *vm, char* address);//done
int BT(brain10 *vm, char arg[]);//done
void BU(brain10 *vm, char arg[]);//done

int GD(brain10 *vm, char* address, FILE *file); //done
int PD(brain10 *vm, char* address); //done
void AD(brain10 *vm, char* address); //done
void SU(brain10 *vm, char* address); //done
void MU(brain10 *vm, char* address); //done
void DI(brain10 *vm, char* address); //done

void AS(brain10 *vm); //done
void SS(brain10 *vm); //done
void MS(brain10 *vm); //done
void DS(brain10 *vm); //done

/* project 2 */
int SD(brain10* vm, list* sndQ, list* rcvQ, list* rdyQ, char* targetPID);
int RC(brain10* vm, list* sndQ, list* rcvQ, list* rdyQ, char* targetPID);
void GP(brain10 *vm);

/* project 3 */
void LS(brain10* vm, int address);
void ST(brain10* vm, int address);
int PE(brain10* vm, int address);
int VE(brain10* vm, int address);
void SI(brain10* vm, int address);

/* project 4 */
void HA();

#endif

